{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit AVRenderer;

interface

uses AHMTypes, Canvas, Colour, Playlist;

const
  DEFAULT_FWD_SKIP = 30; // Default 30 second skip ahead
  DEFAULT_BWD_SKIP = 10; // Default 10 second skip backwards

type
  TAHMMediaError = (meNone, meInstallationBroken, meUnsupportedMedia,
                    meUnsupportedHardware, meExternalError, meStreamEnded);
  TAHMMediaState = (msStopped, msPaused, msSeeking, msPlaying);
  TAHMMediaSignal = (msigNext, msigPrev, msigEnd, msigAbort, msigError);

  TAHMAVRenderer = class
  private
    FVolume: Integer;
    FMediaStream: TObject; // Avoid circular reference
    FPlaylist: TAHMPlaylist;
    FBackgroundColour: TAHMCanvasColour;
    FLastUpdated: TAHMTimestamp;
    FUpdateRequired: Boolean;
    FSettingPosition: Boolean;
    FLastPositioned: TAHMTimestamp;
  protected
    FFullscreen: Boolean;
    FPositionInterval: TAHMTimestamp;
    function GetMuted: Boolean;
    function GetMediaState: TAHMMediaState;
    procedure SetMediaState(State: TAHMMediaState);
    procedure SetLastError(Error: TAHMMediaError);
    function GetDuration: LongInt; virtual;
    function GetPosition: LongInt; virtual;
    function GetChapterCount: Integer; virtual;
    procedure SetPosition(Position: LongInt); virtual;
    procedure SetVolume(Volume: Integer); virtual;
    function OkayToPositionMedia: Boolean;
  public
    constructor Create;
    destructor Destroy; override;
    property MediaState: TAHMMediaState read GetMediaState;
    property BackgroundColour: TAHMCanvasColour read FBackgroundColour write FBackgroundColour;
    property Playlist: TAHMPlaylist read FPlaylist write FPlaylist;
    property Muted: Boolean read GetMuted;
    property Volume: Integer read FVolume write SetVolume;
    property Duration: LongInt read GetDuration;
    property Position: LongInt read GetPosition write SetPosition;
    property ChapterCount: Integer read GetChapterCount;
    property LastError: TAHMMediaError write SetLastError;
    property UpdateRequired: Boolean read FUpdateRequired;
    procedure SetStreamOwner(MediaStream: TObject); // Avoid circular reference
    procedure SignalMediaEvent(EventType: TAHMMediaSignal);
    procedure ReleaseResources; virtual;
    procedure UpdateMediaState; virtual;
    procedure UpdateRendererSettings; virtual;
    procedure Render(Rect: TAHMRectF; Shade: TAHMCanvasShade; Gamma: TAHMCanvasColour;
                     XScale, YScale: Single; XFlip, YFlip: Boolean); virtual;
    function Play: Boolean; virtual;
    function Pause: Boolean; virtual;
    function Stop: Boolean; virtual;
    function SkipForward: Boolean; virtual;
    function SkipBackward: Boolean; virtual;
    function FastForward: Boolean; virtual;
    function Rewind: Boolean; virtual;
    function NextChapter: Boolean; virtual;
    function PreviousChapter: Boolean; virtual;
    function Mute: Boolean; virtual;
    function UnMute: Boolean; virtual;
    function MenuActive: Boolean; virtual;
    function MenuReturn: Boolean; virtual;
    function MenuExit: Boolean; virtual;
    function MenuSelect: Boolean; overload; virtual;
    function MenuSelect(X, Y: Single): Boolean; overload; virtual;
    function MenuNavigate(Direction: TAHMDirection): Boolean; overload; virtual;
    function MenuNavigate(X, Y: Single): Boolean; overload; virtual;
  end;

implementation

uses ApplicationManager, MediaManager, DirectXHelper, Timing;

constructor TAHMAVRenderer.Create;
begin
  inherited Create;

end;

destructor TAHMAVRenderer.Destroy;
begin
  ReleaseResources;

  inherited Destroy;
end;

function TAHMAVRenderer.GetMuted: Boolean;
begin
  Result := ApplicationManagerInstance.MediaManager.Muted;
end;

function TAHMAVRenderer.GetMediaState: TAHMMediaState;
begin
  if Assigned(FMediaStream) then
    Result := TAHMMediaStream(FMediaStream).MediaState
  else
    Result := msStopped;
end;

procedure TAHMAVRenderer.SetMediaState(State: TAHMMediaState);
begin
  if Assigned(FMediaStream) then
    TAHMMediaStream(FMediaStream).MediaState := State;
end;

procedure TAHMAVRenderer.SetLastError(Error: TAHMMediaError);
begin
  if Assigned(FMediaStream) then
    TAHMMediaStream(FMediaStream).LastError := Error;
end;

function TAHMAVRenderer.GetDuration: LongInt;
begin
  // This is defined by descendant renderers
  Result := 0;
end;

function TAHMAVRenderer.GetPosition: LongInt;
begin
  // This is defined by descendant renderers
  Result := 0;
end;

procedure TAHMAVRenderer.SetPosition(Position: LongInt);
begin
  // This is implemented by descendant renderers
end;

function TAHMAVRenderer.GetChapterCount: Integer;
begin
  // This is defined by descendant renderers
  Result := 0;
end;

procedure TAHMAVRenderer.SetVolume(Volume: Integer);
begin
  // Descendant renderers may choose to implement, but must call inherited method
  FVolume := Volume;
end;

function TAHMAVRenderer.OkayToPositionMedia: Boolean;
begin
  // Set default result - okay to Seek
  Result := True;

  // Did we already set position for this media?
  if not FSettingPosition then
  begin
    // Not yet, timestamp this seek request
    FSettingPosition := True;
    FLastPositioned := TimerInstance.CurrentTimeStamp;
  end
  else
  begin
    // Check elapsed time since last seek request. If sufficient time has
    // elapsed then we can perform the seek. This prevents keyboard buffer
    // filling up whilst we attempt to continually seek media if user holds
    // down fast forward or rewind keys/buttons
    if TimerInstance.HasDurationElapsed(FLastPositioned, FPositionInterval) then
      FLastPositioned := TimerInstance.CurrentTimeStamp
    else
      Result := False;
  end;
end;

procedure TAHMAVRenderer.SetStreamOwner(MediaStream: TObject);
begin
  FMediaStream := MediaStream;
end;

procedure TAHMAVRenderer.SignalMediaEvent(EventType: TAHMMediaSignal);
begin
  if Assigned(FMediaStream) then
    TAHMMediaStream(FMediaStream).SignalEvent(EventType);
end;

procedure TAHMAVRenderer.ReleaseResources;
begin
  // This is defined by descendant renderers
end;

procedure TAHMAVRenderer.UpdateMediaState;
begin
  // This is defined by descendant renderers
end;

procedure TAHMAVRenderer.UpdateRendererSettings;
begin
  // This is defined by descendant renderers
end;

procedure TAHMAVRenderer.Render(Rect: TAHMRectF; Shade: TAHMCanvasShade; Gamma: TAHMCanvasColour;
                                XScale, YScale: Single; XFlip, YFlip: Boolean);
begin
  // Determine whether we're being asked to render fullscreen or not
  FFullScreen := (Rect.Width >= 1.0) and (Rect.Height >= 1.0);

  // If we're currently playing and fullscreen, don't invoke the screen saver
  if FFullScreen and (MediaState = msPlaying) then
    ApplicationManagerInstance.UIManager.ScreenSaver.DidSomething;

  // If media is stopped then just render background colour
  if (MediaState = msStopped) and Assigned(FBackgroundColour) then
    DirectXInstance.ClearRect(Rect, FBackgroundColour);

  // Set out update flag - should only perform one update per frame
  FUpdateRequired := False;
  if FLastUpdated <> TimerInstance.CurrentTimeStamp then
  begin
    FLastUpdated := TimerInstance.CurrentTimeStamp;
    FUpdateRequired := True;
  end;

  // Custom rendering is defined by descendant renderers
end;

function TAHMAVRenderer.Play: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.Pause: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.Stop: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.SkipForward: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.SkipBackward: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.FastForward: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.Rewind: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.NextChapter: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.PreviousChapter: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.Mute: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.UnMute: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.MenuActive: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.MenuReturn: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.MenuExit: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;


function TAHMAVRenderer.MenuSelect: Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.MenuSelect(X, Y: Single): Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.MenuNavigate(Direction: TAHMDirection): Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

function TAHMAVRenderer.MenuNavigate(X, Y: Single): Boolean;
begin
  // This is defined by descendant renderers
  Result := False;
end;

end.
